<?php


namespace app\api\service\impl;


use app\api\logic\CouponLogic;
use app\api\logic\FreightLogic;
use app\api\service\OrderStrategy;
use app\model\pms\Goods;
use app\model\user\UserAddress;
use plugin\coupon\app\admin\logic\CouponReceiveLogLogic;
use plugin\coupon\app\model\CouponReceiveLog;
use support\exception\BadException;
use support\utils\Decimal;
use support\utils\Time;

class AbstractOrderStrategy implements OrderStrategy
{
    /**
     * @var CouponLogic
     */
    protected CouponLogic $couponLogic;
    /**
     * @var CouponReceiveLogLogic
     */
    protected CouponReceiveLogLogic $couponReceiveLogLogic;

    public function __construct()
    {
        $this->couponLogic = new CouponLogic();
        $this->couponReceiveLogLogic = new CouponReceiveLogLogic();
    }

    public function preCreateOrder($data)
    {
        throw new BadException("preCreateOrder未实现");
    }

    public function createOrder($data)
    {
        throw new BadException("createOrder未实现");
    }


    /**
     * @param  $coupon_receive_log_id
     * @param  $total_price
     */
    protected function calCoupon($coupon_receive_log_id, $total_price)
    {
        $couponInfo = $this->couponReceiveLogLogic->findCoupon($coupon_receive_log_id);
        if ($couponInfo['coupon']['type'] == 1) {
            return [
                'discountAmount' => $couponInfo['coupon']['amount'],
                'coupon_receive_log_id' => $coupon_receive_log_id,
                'coupon_id' => $couponInfo['coupon_id'],
                'couponInfo' => $couponInfo,
            ];
        } else {
            //折扣券百分比
            $discountAmount = Decimal::newDecimal($total_price)->subtract(
                Decimal::newDecimal($total_price)->multiply(
                    Decimal::newDecimal($couponInfo['coupon']['discount'])->divide(100)
                )
            )->getValue();

            if ($discountAmount > $couponInfo['coupon']['max_discount_amount']) {
                //超过最大抵扣金额
                $discountAmount = $couponInfo['coupon']['max_discount_amount'];
            }
            return [
                'discountAmount' => $discountAmount,
                'coupon_receive_log_id' => $coupon_receive_log_id,
                'coupon_id' => $couponInfo['coupon_id'],
                'couponInfo' => $couponInfo,
            ];
        }
    }

    /**
     * 计算每个商品平摊的卡券金额
     * @param array $collectCouponGoodsResult
     * @param string $couponAmount 总优惠金额
     * @param array $goodsList
     * @return mixed
     */
    protected function calGoodsCouponAmount($collectCouponGoodsResult, $couponAmount, $goodsList)
    {
        $totalPrice = $collectCouponGoodsResult['totalPrice']; //参与优惠券范围的商品合计金额
        $allocationAmount = Decimal::newDecimal($couponAmount); //参与优惠券范围的商品合计金额
        $collectGoods = $collectCouponGoodsResult['collectGoods']; //参与优惠券范围的商品信息
        $lastKey = count($goodsList) - 1;
        foreach ($goodsList as $key => &$item) {
            $item['coupon_amount'] = 0;
            if (!isset($collectGoods[$item['goods_id']]) || !$collectGoods[$item['goods_id']]) {
                continue;
            }
            $curCalc = $collectGoods[$item['goods_id']];
            if ($lastKey == $key) {
                //最后一次 剩多少摊多少
                $item['coupon_amount'] = $allocationAmount->getValue();
            } else {
                //按比例摊  比如卡券抵扣100  该商品实际50 合计金额200  那就是 50/200*100 = 25
                $item['coupon_amount'] = Decimal::newDecimal($curCalc)
                    ->divide($totalPrice)
                    ->multiply($couponAmount)
                    ->getValue();
                $allocationAmount->subtract($item['coupon_amount']);
            }
        }
        return $goodsList;
    }

    protected function getAddress($uid, $address_id)
    {
        if ($address_id) {
            $addressWhere = ['id' => $address_id, 'user_id' => $uid];
        } else {
            $addressWhere = ['is_default' => 1, 'user_id' => $uid];
        }
        $userAddress = UserAddress::where($addressWhere)
            ->order('create_time desc')
            ->find();
        if (!$userAddress) {
            $userAddress = UserAddress::where(['user_id' => $uid])
                ->order('create_time desc')
                ->find();
        }
        return $userAddress; //用户地址信息
    }

    /**
     * 计算运费
     * @param $address
     * @param $goodsList
     * @return array
     */
    protected function calcFreight($address, $goodsList)
    {
        if (!$address) {
            return [
                'intra_region' => true,
                'fee' => 0
            ];
        }

        $feeCalc = Decimal::newDecimal();
        $logic = new FreightLogic();
        $intraRegion = true;
        foreach ($goodsList as $item) {
            //免费
            if ($item['freight_type'] === Goods::FREIGHT_TYPE_FREE) {
                continue;
            }
            //运费模板
            if ($item['freight_type'] === Goods::FREIGHT_TYPE_TEMPLATE) {
                $intraRegion = $logic->checkAddress($item['shipping_tpl_id'], $address['city_code']);
                if ($intraRegion && $item['shipping_tpl_id'] > 0) {
                    $feeCalc->add($logic->calcFreightByShippingTpl($item, $address['city_code']));
                }
            }
            //固定运费
            if ($item['freight_type'] === Goods::FREIGHT_TYPE_FIXED) {
                $feeCalc->add($item['freight']);
            }
        }

        return [
            'intra_region' => $intraRegion,
            'fee' => $feeCalc->getValue()
        ];
    }


    protected function usedCoupon($uid, $coupon_receive_log_id, $order_id)
    {
        if ($coupon_receive_log_id > 0) {
            $flag = CouponReceiveLog::where([
                'id' => $coupon_receive_log_id,
                'user_id' => $uid,
                'status' => CouponReceiveLog::STATUS_NO_USED
            ])->update([
                'status' => CouponReceiveLog::STATUS_USED,
                'order_id' => $order_id,
                'used_time' => Time::now(),
            ]);
            if (!$flag) {
                throw new BadException("卡券使用失败,下单失败");
            }
        }
    }
}